package com.blazingdb.calcite.catalog.domain;

import org.hibernate.annotations.Cascade;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
 * <h1>Representation of a Database</h1>
 * This domain class is a database which stores a map of tables that it contains. It is named but
 * currentl we are always defaulting to the same database called "main" as can be seen in
 * {@see com.blazingdb.calcite.application.ApplicationContext}.
 *
 * @author felipe
 *
 */
@Entity
@Table(name = "blazing_catalog_database")
public class CatalogDatabaseImpl implements CatalogDatabase {
	/**
	 * A value generated by the database which hibernate is using to persist schemas.
	 */
	@Id @GeneratedValue @Column(name = "id") private Long id;

	/**
	 * The name of the table;
	 */
	@Column(name = "name", nullable = false) private String name;

	/**
	 * A map of names to tables which stores all of the tables that exist inside of this database;
	 */
	@OneToMany(fetch = FetchType.EAGER, mappedBy = "database", orphanRemoval = true)
	@Cascade({org.hibernate.annotations.CascadeType.ALL})
	@MapKey(name = "name")
	private Map<String, CatalogTableImpl> databaseTables;

	/*
	@ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = "schema_id")
	private CatalogSchemaImpl schema;


	public CatalogSchemaImpl getSchema() {
		return schema;
	}

	public void setSchema(CatalogSchemaImpl schema) {
		this.schema = schema;
	}

	*/

	/**
	 * Empty constructor just sets up an empty HashMap for the tables.
	 */
	public CatalogDatabaseImpl() { this.databaseTables = new HashMap<String, CatalogTableImpl>(); }
	/**
	 * Constructor that sets up the HashMap for tables and sets the name.
	 * @param name the name we are to give this database.
	 */
	public CatalogDatabaseImpl(String name) {
		this.name = name;
		this.databaseTables = new HashMap<String, CatalogTableImpl>();
	}

	public Long
	getId() {
		return id;
	}

	public void
	setId(Long id) {
		this.id = id;
	}

	@Override
	public String
	getDatabaseName() {
		return this.name;
	}

	public void
	setDatabaseName(String name) {
		this.name = name;
	}

	/**
	 * Gets the different tables from the hashmap and returns them as a set
	 * as some of our uses of this class were expecting
	 * @return The complete set of tables that are found in the {@link #databaseTables}
	 */
	public Set<CatalogTable>
	getTables() {
		Set<CatalogTable> tempTables = new LinkedHashSet<CatalogTable>();
		tempTables.addAll(this.databaseTables.values());
		return tempTables;
	}

	public Map<String, CatalogTableImpl>
	getDatabaseTables() {
		return this.databaseTables;
	}

	public void
	setDatabaseTables(Map<String, CatalogTableImpl> tables) {
		this.databaseTables = tables;
	}

	// TODO: handle the situation that arises when a table does not exist
	/**
	 * Gets a table by name
	 * @return the table that has this name
	 */
	@Override
	public CatalogTableImpl
	getTable(String tableName) {
		// TODO Auto-generated method stub
		return this.databaseTables.get(tableName);
	}

	/**
	 * @return The names of all the tables in the database by getting them
	 * from the keySet() of {@link #databaseTables}
	 */
	@Override
	public Set<String>
	getTableNames() {
		// TODO Auto-generated method stub
		Set<String> tableNames = new LinkedHashSet<String>();
		tableNames.addAll(this.databaseTables.keySet());
		return tableNames;
	}
	/**
	 * Adds a new table to this database.
	 * @param table the table to be added to the database.
	 */
	public void
	addTable(CatalogTableImpl table) {
		// TODO Auto-generated method stub
		this.databaseTables.put(table.getTableName(), table);
	}
	/**
	 * Removes a table from this database.
	 * @param table the table to be removed.
	 */
	public void
	removeTable(CatalogTableImpl table) {
		this.databaseTables.remove(table.getTableName());
	}
	public void
	removeTable(String tableName) {
		this.databaseTables.remove(tableName);
	}
}
